package menu
{
	import com.*;
	import com.Logging.ClientAction;
	import com.Logging.ClientActionType;
	import events.GCEvent;
	import data.*;
	import flash.accessibility.AccessibilityProperties;
	import flash.display.Bitmap;
	import flash.display.Shape;
	import ui.button.GCButton;
	import ui.GCNumberSelector;
	import ui.popup.GCWorkerTransferPopup;
	import ui.textfield.GCTextField;
	import ui.textfield.GCStylizedText;
	
	import flash.display.Sprite;
	import flash.events.MouseEvent;
	import flash.utils.Dictionary;
	
	
	/**
	 * Menu screen where the player assigns their worker to various
	 * harvest buildings in their trade post.
	 * 
	 * Main components will consist of:
	 * Label showing idle workers in city
	 * Component that allows player to adjust workers in a building
	 * Display showing gathering rate of workers
	 * Menu to allow transfer of workers between the ship and city
	 */
	public class GCWorkerAssignMenu extends Sprite implements GCSuperMenu
	{
		/*
		 * Keep track of the total number of idle workers and
		 * all workers stationed at this city.
		 */
		private var _idleWorkers:uint;
		private var _totalWorkers:uint;
		private var _workersOnShip:uint;

		private var _workerStatsArea:Sprite;
		private var _idleWorkersDisplay:GCTextField;
		private var _totalWorkersDisplay:GCTextField;

		/*
		 * In order to make it easy for the user to cancel changes
		 * they make here, we need to make a copy of the logical buildings.
		 * Only flush changes to actual buildings if they hit confirm.
		 * (WARNING this restricts us to having only one particular building id per
		 * city, i.e. can't have 2 farms in same location)
		 */
		 
		 
		/*
		 * Keep track of gathering rate
		 */
		private var _resourceRateList:Dictionary;		// Dictionary: key=ResourceId, value=GatherRate
		private var _resourceRateText:Dictionary;		// Dictionary: key=ResourceId, value=TextField to display rate
		 
		 
		/*
		 * Keeping track of the worker assign buttons and
		 * buildings.
		 */
		private var _buildingsList:Dictionary;			// Dictionary: key=ScrollerComp, value=LogicalBuildingClone
		private var _buildingButtonsArea:Sprite;		// An area for the buttons.
		private var _buildingButtonIncreaseEnabled:Boolean;
		
		/*
		 * Components related to displaying gather rate.
		 */
		private var _gatherRateArea:Sprite;
		
		/*
		 * Items to allow the player to transfer workers to
		 * and from the ship.
		 */
		private var _workerTransferPopup:GCWorkerTransferPopup;

		
		/*
		Buttons to confirm or cancel the changes made by a
		player.
		*/
		private var _confirmButton:GCButton;
		private var _workerTransferButton:GCButton;
		private var _exitButton:GCButton;
		
		public function GCWorkerAssignMenu() 
		{
			// Background
			this.graphics.beginFill(0x0066cc);
			this.graphics.drawRect(0, 0, GCMainDisplay.WIDTH, GCMainDisplay.HEIGHT);
			this.graphics.endFill();

			// Building Area
			_buildingButtonsArea = new Sprite();
			
			// Rate Area
			_gatherRateArea = new Sprite();
			
			// Worker Stats
			_workerStatsArea = new Sprite();
			_idleWorkers = 0;
			_idleWorkersDisplay = new GCTextField();
			_totalWorkersDisplay = new GCTextField();
			
			// Menu Buttons
			_workerTransferButton = new GCButton(onTransferWorkers);
			_confirmButton = new GCButton(onConfirm);
			_exitButton = new GCButton(onExit);
			
			// Worker Transfer Popup
			_workerTransferPopup = new GCWorkerTransferPopup();
			
			init();
		}
		
		private function init():void
		{
			var areaBackground:Sprite;
			
			// Building Area
			areaBackground = GCResources.getMaskedCanvasBackground(400, 200);
			_buildingButtonsArea.addChild(areaBackground);
			_buildingButtonsArea.x = 20;
			_buildingButtonsArea.y = 80;
			
			var buildingsLabel:GCStylizedText = new GCStylizedText();
			buildingsLabel.text = "Assign Workers to your harvest buildings to gather resources:";
			buildingsLabel.setBgStyle(GCStylizedText.STYLE_ONE, 300, 50);
			buildingsLabel.y = -1 * buildingsLabel.height;
			_buildingButtonsArea.addChild(buildingsLabel);			
			
			// Rate Area
			areaBackground = GCResources.getMaskedCanvasBackground(200, 200);
			_gatherRateArea.addChild(areaBackground);
			var gatherRateLabel:GCStylizedText = new GCStylizedText();
			gatherRateLabel.text = "Gathering Rate";
			gatherRateLabel.setBgStyle(GCStylizedText.STYLE_ONE, areaBackground.width, 50);
			gatherRateLabel.y = -1 * gatherRateLabel.height;
			_gatherRateArea.addChild(gatherRateLabel);
			_gatherRateArea.x = 500;
			_gatherRateArea.y = _buildingButtonsArea.y;			
			
			// Worker Stats
			areaBackground = GCResources.getMaskedCanvasBackground(300, 100);
			_workerStatsArea.addChild(areaBackground);
			var workerStatsLabel:GCStylizedText = new GCStylizedText();
			workerStatsLabel.text = "Workers in Command";
			workerStatsLabel.setBgStyle(GCStylizedText.STYLE_ONE, areaBackground.width, 50);
			workerStatsLabel.y = -1 * workerStatsLabel.height;
			_workerStatsArea.addChild(workerStatsLabel);
			_workerStatsArea.x = _buildingButtonsArea.x;
			_workerStatsArea.y = 375;
						
			var idleWorkersLabel:GCTextField = new GCTextField();
			idleWorkersLabel.text = "Number of idle workers:";
			idleWorkersLabel.x = 10;
			idleWorkersLabel.y = 20;
			idleWorkersLabel.height = 30;
			_idleWorkersDisplay.x = idleWorkersLabel.x + idleWorkersLabel.width;
			_idleWorkersDisplay.y = idleWorkersLabel.y;
			_idleWorkersDisplay.height = idleWorkersLabel.height;
			_workerStatsArea.addChild(idleWorkersLabel);
			_workerStatsArea.addChild(_idleWorkersDisplay);
						
			var totalWorkersLabel:GCTextField = new GCTextField();
			totalWorkersLabel.text = "Total workers at this city:";
			totalWorkersLabel.x = idleWorkersLabel.x;
			totalWorkersLabel.y = idleWorkersLabel.y + idleWorkersLabel.height + 10;
			totalWorkersLabel.height = idleWorkersLabel.height;
			_totalWorkersDisplay.x = totalWorkersLabel.x + totalWorkersLabel.width;
			_totalWorkersDisplay.y = totalWorkersLabel.y;
			_totalWorkersDisplay.height = totalWorkersLabel.height;
			_workerStatsArea.addChild(totalWorkersLabel);
			_workerStatsArea.addChild(_totalWorkersDisplay);
			
			// Worker Transfer Popup
			_workerTransferPopup.addEventListener(GCEvent.POPUP_CLOSED_EVENT, onTransferPopupClose);
			
			// Buttons
			_confirmButton.loadGraphic(GCResources.plate, 150, 30);
			_confirmButton.loadText("Exit Menu");
			_confirmButton.x = _gatherRateArea.x;
			_confirmButton.y = this.height - 100;
			
			_exitButton.loadGraphic(GCResources.plate, 150, 30);
			_exitButton.loadText("Cancel");
			_exitButton.y = _confirmButton.y;
			_exitButton.x = _confirmButton.x + _confirmButton.width;
			
			_workerTransferButton.loadGraphic(GCResources.plate, 150, 30);
			_workerTransferButton.loadText("Transfer Workers");
			_workerTransferButton.x = _confirmButton.x;
			_workerTransferButton.y = this.height - 150;
			
			// Add the UI elements
			this.addChild(_buildingButtonsArea);
			this.addChild(_gatherRateArea);
			this.addChild(_workerStatsArea);
			this.addChild(_workerTransferButton);
			this.addChild(_confirmButton);
		}		
		
		/**
		 * In order to display this menu correctly for a particular city,
		 * we need to get what buildings the player has constructed at this city
		 * as well as the distribution of workers per building. Appropriate parameters
		 * must be passed to here before the menu can be displayed to player.
		 * 
		 * @param buildings
		 * 		The list of GCCityBuildings (those that can harvest resources) that the player
		 * 		has constructed. (Probably should be a copy of the objects so player can cancel changes
		 * 		easily)
		 */
		public function openMenu(buildings:Vector.<GCCityBuilding>, numAtCity:int, numOnShip:int):void
		{
			_idleWorkers = numAtCity;
			_totalWorkers = numAtCity;
			_workersOnShip = numOnShip;
			_buildingsList = new Dictionary();
			_resourceRateList = new Dictionary();
			_resourceRateText = new Dictionary();

			trace("GCWorkerAssignMenu-- " + buildings.length);
			
			var xPos:int = 10;
			var yPos:int = 0;
			/*
			 * For each building that was passed to us, we will need to create a selector component
			 */
			for each(var building:GCCityBuilding in buildings)
			{
				// If building is not harvest type, cannot assign workers to it!
				if (building.getType() != GCBuildingData.BUILDING_TYPE_HARVEST)
				{
					continue;
				}
				
				/*
				 * Count up the total number of workers and set up the gathering rates
				 * from the initial data passed in.
				 */
				var workersAtBuilding:int = building.numWorkers
				_idleWorkers -= workersAtBuilding;
				
				/*
				 * Here we will set up the selector component for a particular
				 * building, which allows the player to increase or decrease.
				 */
				var selector:GCNumberSelector = new GCNumberSelector(building.buildingId);
				selector.x = xPos;
				selector.y = yPos;
				_buildingButtonsArea.addChild(selector);
				
				xPos += selector.width + 10;
				if (xPos > _buildingButtonsArea.width)
				{
					yPos += selector.height + 10;
					xPos = 0;
				}
				
				// Set the value to what was found in the building.
				selector.setValue(workersAtBuilding);
				
				// Add to the dictionary
				_buildingsList[selector] = building;
				
				selector.addEventListener(GCEvent.VALUE_CHANGED_EVENT, onWorkerReassign);
				
				/*
				Define the resources that can be gathered.
				*/
				var resourceId:uint = building.getHarvestableResource();
				if (!_resourceRateList.hasOwnProperty(building.buildingId))
				{
					_resourceRateList[resourceId] = building.getRate();
				}
				else
				{
					var val:int = _resourceRateList[resourceId];
					_resourceRateList[resourceId] = val + building.getRate();
				}
			}
			
			xPos = 5;
			yPos = 10;
			for (var key:Object in _resourceRateList)
			{
				var id:uint = (key as uint);
				var resourceName:String = GCItemData.getNameFromId(id);
				var resourceLabel:GCTextField = new GCTextField();
				resourceLabel.text = resourceName;
				resourceLabel.x = xPos;
				resourceLabel.y = yPos;
				
				var resourceRateDisplay:GCTextField = new GCTextField();
				resourceRateDisplay.text = String(_resourceRateList[id]);
				resourceRateDisplay.x = resourceLabel.x + resourceLabel.width;
				resourceRateDisplay.y = resourceLabel.y;
				
				// Add the text field to the dictionary so we can access it later.
				_resourceRateText[id] = resourceRateDisplay;
				
				xPos = 0;
				yPos += resourceLabel.height;
				
				_gatherRateArea.addChild(resourceLabel);
				_gatherRateArea.addChild(resourceRateDisplay);
			}
			
			/*
			 * Update the label showing idle and total workers
			 */
			_buildingButtonIncreaseEnabled = (_idleWorkers != 0);
			toggleSelectorIncrease(_buildingButtonIncreaseEnabled);
			_idleWorkersDisplay.text = String(_idleWorkers);
			_totalWorkersDisplay.text = String(_totalWorkers);
		}
		
		/**
		 * Clean up the menu
		 */
		public function closeMenu():void
		{
			/*
			 * Remove all buttons from the building buttons area
			 * and clear up all information in the gathering rate.
			 */
			for (var component:Object in _buildingsList)
			{
				var scroller:GCNumberSelector = (component as GCNumberSelector);
				_buildingButtonsArea.removeChild(scroller);
				scroller.removeEventListener(GCEvent.VALUE_CHANGED_EVENT, onWorkerReassign);
			}
			
			/*
			 * Remove text from the gather rate area
			 */
			while (_gatherRateArea.numChildren > 2)
			{
				_gatherRateArea.removeChildAt(2);
			}
		}
		//----------------------------------------------------------------------
		//	PUBLIC FUNCTIONS
		//----------------------------------------------------------------------				
		
		/**
		 * Method to call to refresh any dynamic parts on the menu
		 */
		public function refresh():void
		{
			
		}
		
		//----------------------------------------------------------------------
		//	PRIVATE FUNCTIONS
		//----------------------------------------------------------------------
		
		/**
		 * A function to toggle on and off whether to allow the selector
		 * components to increase their values. Is dependent on whether
		 * there are any 
		 * 
		 * @param	enableIncrease
		 * 		Boolean of whether we want the selectors to be able to increase their values.
		 */
		private function toggleSelectorIncrease(enableIncrease:Boolean):void
		{
			_buildingButtonIncreaseEnabled = enableIncrease;
			
			for (var component:Object in _buildingsList)
			{
				var scroller:GCNumberSelector = (component as GCNumberSelector);
				scroller.setEnableIncrease(enableIncrease);
			}
		}		
		
		private function checkTutorialAssignedWorkers(template:uint, bldgId:uint, numWorkers:uint):void
		{
			var quest:GCQuest = GCPlayState.tutorialSequence.getTutorialQuestFromTemplate(template);
			trace("GCWorkerAssignMenu-- Checking if enough worker are at the building");
			if (quest != null)
			{
				var goalBldgId:uint = quest.goalId;
				var goalNumWorkers:uint = quest.goalQuantity;
				if (goalBldgId == bldgId && goalNumWorkers <= numWorkers)
				{
					GCPlayState.dispatchTutorialComplete(template);
				}
			}
		}	
		
		//----------------------------------------------------------------------
		//	EVENT HANDLERS
		//----------------------------------------------------------------------
		/**
		 * In order for changes in worker assignment to take place, the player
		 * must select confirm. Otherwise, we will ignore them.
		 * 
		 * @param	event
		 */
		private function onConfirm(event:MouseEvent):void
		{
			dispatchEvent(new GCEvent(GCEvent.CONFIRM_MENU_EVENT));
		}
		
		private function onExit(event:MouseEvent):void
		{
			dispatchEvent(new GCEvent(GCEvent.CANCEL_MENU_EVENT));
		}		
		
		/**
		 * Listens for when any worker has be reassigned, going
		 * from idle to harvesting or vis versa. Logic to recalculate the
		 * gathering rates is called from here.
		 * 
		 * @param	event
		 */
		private function onWorkerReassign(event:GCEvent):void
		{
			trace("Number of workers has changed!");
			var alteredSelector:GCNumberSelector = event.currentTarget as GCNumberSelector;
			
			/*
			 * We will search for the actual building object that was attached to the
			 * selector component in the dictionary. This will allow us to easily see
			 * whether the number of workers increased or decreased.
			 */
			var alteredBuilding:GCCityBuilding = _buildingsList[alteredSelector];
			var newNumberAtBuilding:uint = alteredSelector.value;
			var oldNumberAtBuilding:uint = alteredBuilding.numWorkers;
			
			var pid:uint = GCPlayState.getPlayerId();
			var lid:uint = GCPlayState.getCurrentCity().getId();
			if (newNumberAtBuilding > oldNumberAtBuilding)
			{
				// A previously idle worker was added to a building
				_idleWorkers--;
				
				//DATABASE CALL- change a worker from idle to at a harvest building
				if (!GCConstants.DEBUG_MODE)
				{
					GCUtil.updateCrew(pid, lid, GCBuildingData.BUILDING_NONE, lid, alteredBuilding.buildingId, 1, function(code:uint, data:Object):void
					{
						trace("DATABASE-- made a worker work at harvest building");
					});
				}
			}
			else
			{
				// A worker was made idle
				_idleWorkers++;
				
				//DATABASE CALL- change a worker from working at a harvest building to being idle
				if (!GCConstants.DEBUG_MODE)
				{
					GCUtil.updateCrew(pid, lid, alteredBuilding.buildingId, lid, GCBuildingData.BUILDING_NONE, 1, function(code:uint, data:Object):void
					{
						trace("DATABASE-- made a worker idle");
					});
				}
			}
			
			if (GCConstants.LOGGING_DATA)
			{
				var o:Object = new Object();
				o["diff"] = newNumberAtBuilding - oldNumberAtBuilding;
				o["job"] = alteredBuilding.buildingId;
				GCPlayState.logger.LogAction(new ClientAction(ClientActionType.CHANGE_WORKERS, o));
			}

			/*
			First iteration to check new rates and calculate the number
			of workers who are harvesting.
			*/
			var resourceId:uint = alteredBuilding.getHarvestableResource();
			var newRate:uint = alteredBuilding.predictNewRate(newNumberAtBuilding)
			var rateDelta:int = newRate - alteredBuilding.getRate();
			_resourceRateList[resourceId]  =  _resourceRateList[resourceId] + rateDelta;
			(_resourceRateText[resourceId] as GCTextField).text = String(_resourceRateList[resourceId]);
			
			/*
			Check if we need to enable or disable the increase functionality for all 
			scrollers. Disable if we find idle workers is at zero.
			
			Reenable only if they were disabled before.
			*/
			if (_idleWorkers > 0 && !_buildingButtonIncreaseEnabled)
			{
				toggleSelectorIncrease(true);
			}
			else if (_idleWorkers == 0 && _buildingButtonIncreaseEnabled)
			{
				toggleSelectorIncrease(false);
			}
			
			// Changes the number of workers and gather rate at building
			alteredBuilding.numWorkers = newNumberAtBuilding;
			_idleWorkersDisplay.text = String(_idleWorkers);
			
			/*
			 * Roy-- tutorial
			 * We simply check if the player has assigned the correct number of workers
			 * to the specified building.
			 */
			if (GCPlayState.tutorialSequence.currentTutorialStage == GCTutorial.STAGE_BUILD_GATHER)
			{
				checkTutorialAssignedWorkers(GCQuestData.QUEST_TEMPLATE_TUTORIAL_13, alteredBuilding.buildingId, newNumberAtBuilding);
			}
		}
		
		/**
		 * Triggered when the player wants to move workers from their ship
		 * to the current city they are docked at.
		 * 
		 * @param	event
		 */
		private function onTransferWorkers(event:MouseEvent):void
		{
			_workerTransferPopup.openPopup(_workersOnShip, _idleWorkers);
			GCPlayState.disableScreen(_workerTransferPopup);
		}
		
		/**
		 * Handle when the popup has been closed
		 * 
		 * @param	event
		 */
		private function onTransferPopupClose(event:GCEvent):void
		{
			/*
			 * Figure out the new number of workers who have been transferred
			 * into or out of the city.
			 */
			var newNumberIdle:int = _workerTransferPopup.workersIdleAtCity;
			var delta:int = newNumberIdle - _idleWorkers;			
			_totalWorkers += delta;
			_idleWorkers = newNumberIdle;
			_workersOnShip = _workerTransferPopup.workersAtShip;
			
			/*
			 * A change in the number of idle workers will require us to check
			 * whether we need to allow or disallow adding additional
			 * workers to harvest buildings.
			 */
			if (_idleWorkers > 0 && !_buildingButtonIncreaseEnabled)
			{
				toggleSelectorIncrease(true);
			}
			else if (_idleWorkers == 0 && _buildingButtonIncreaseEnabled)
			{
				toggleSelectorIncrease(false);
			}
			
			/*
			 * Clean up the popup
			 */
			_workerTransferPopup.closePopup();
			GCPlayState.enableScreen();
			
			/*
			 * Update the label showing idle and total workers
			 */
			_idleWorkersDisplay.text = String(_idleWorkers);
			_totalWorkersDisplay.text = String(_totalWorkers);
			
			/*
			 * Check if the number of total workers in this city have changed.
			 * Here we will change the actual amount of workers
			 */
			var currentCity:GCCity = GCPlayState.getCurrentCity();
			if (currentCity._totalWorkers != _totalWorkers)
			{
				currentCity._totalWorkers = _totalWorkers;
			}
			
			/*
			 * Check if the number of idle workers has changed
			 */
			if (currentCity.idleWorkers != _idleWorkers)
			{
				currentCity.idleWorkers = _idleWorkers;
			}
			
			//DATABASE CALL- change crew from ship to idle in city
			var oldLid:uint;
			var newLid:uint;
			if (delta > 0)
			{
				// Number idle increased, ship decreased
				oldLid = GCCityData.CITY_SHIP;
				newLid = currentCity.getId();
			}
			else
			{
				// Number idle decreased, ship increased
				oldLid = currentCity.getId();
				newLid = GCCityData.CITY_SHIP;
			}
			
			if (!GCConstants.DEBUG_MODE)
			{
				GCUtil.updateCrew(GCPlayState.playerData.getPlayerId(), oldLid, GCBuildingData.BUILDING_NONE,
				newLid, GCBuildingData.BUILDING_NONE, int(Math.abs(delta)), function (code:uint, data:Object):void
				{
					trace("DATABASE-- Transferred workers to and from the ship");
				});
			}
		}
		
		
	}
}